#include "ThreadCache.h"
#include "CentralCache.h"

void* ThreadCache::Allocate(size_t size)
{
    assert(size <= MAX_BYTES);
    //获取对齐字节数
    size_t alignSize = SizeClass::RoundUp(size);
    //获取对应桶
    size_t index = SizeClass::Index(size);
    //如果对应桶里有内存块则pop出来返回
    if(!_freeLists[index].Empty())
    {
        return _freeLists[index].Pop();
    }
    else //没有则向中心缓存申请
    {
        return FetchFromCentralCache(index, alignSize);
    }
}

void ThreadCache::Freelocate(void* ptr, size_t size)
{
    //判断ptr不为空且size不超过MAX_BYTES，然后回收对象到对应链表桶
    assert(ptr);
    assert(size <= MAX_BYTES);
    size_t index = SizeClass::Index(size);
    _freeLists[index].Push(ptr);
    //如果链表长度大于中心缓存批量给的长度，就回收一段list给中心缓存
    if(_freeLists[index].Size() >= _freeLists[index].MaxSize())
    {
        ThreadCache::ReclaimToCentralCache(_freeLists[index], size);
    }
}

void* ThreadCache::FetchFromCentralCache(size_t index, size_t size)
{
    //慢开始反馈调节算法
    /*
    最开始不会一次向central cache要太多，可能用不完
    如果不断有size大小的内存需求，就会不断增长直至上限
    size越大，向central cache申请的batchNum就越小，反之慢慢增长
    */
   //因为如果是小对象一次性给512个也是很多，所以通过对比_size，取最小值，如果_size最小则加1，起到慢增长效果
   size_t batchNum = std::min(_freeLists[index].MaxSize(), SizeClass::NumMoveSize(size));
   if(_freeLists[index].MaxSize() == batchNum)
   {
        _freeLists[index].MaxSize() += 1;
   }

   void* start = nullptr;//申请内存的链表头
   void* end = nullptr;//申请内存的链表尾
   size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, size);
   assert(actualNum >= 1);
   if(actualNum == 1)//如果只有一个对象，则直接返回该对象
   {
        assert(start == end);
        return start;
   }
   else
   {
        //多个则将后面多的放进自由链表桶里，只返回一个对象
        _freeLists[index].PushRange(NextObj(start), end, (actualNum - 1));
        return start;
   }
}

void ThreadCache::ReclaimToCentralCache(FreeList& list, size_t size)
{
        //取一段内存
        void* start = nullptr;
        void* end = nullptr;
        list.PopRange(start, end, list.MaxSize());
        //还给对应span
        CentralCache::GetInstance()->ReleaseListToSpan(start, size);

}
